﻿#region Copyright and License Notice
// Copyright (C)2010-2016 - Rob Levine and other contributors
// http://configgen.codeplex.com
// 
// This file is part of ConfigGen.
// 
// ConfigGen is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// ConfigGen is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License and 
// the GNU Lesser General Public License along with ConfigGen.  
// If not, see <http://www.gnu.org/licenses/>
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using ConfigGen.Core.SettingsLoader;
using Moq;
using NUnit.Framework;

namespace ConfigGen.Core.Tests.SettingsLoader
{
    [TestFixture]
    public class SpreadsheetDataProcessorTests
    {
        [Test]
        public void Ctor001_NullArgThrows()
        {
            Assert.Throws<ArgumentNullException>(() => new SpreadsheetDataProcessor(null));
        }

        [Test]
        public void ProcessDataRows001_NullArgsThrows()
        {
            var mockDataParser = new Mock<ICellDataParser>();
            var itemUnderTest = new SpreadsheetDataProcessor(mockDataParser.Object);
            Assert.Throws<ArgumentNullException>(() => itemUnderTest.ProcessDataRows(null, new List<ExcelColumnInfo>(), new SpreadsheetPreferences()).ToArray(), "Null not allowed: dataRows");
            Assert.Throws<ArgumentNullException>(() => itemUnderTest.ProcessDataRows(new List<object[]>(), null, new SpreadsheetPreferences()).ToArray(), "Null not allowed: columnList");
            Assert.Throws<ArgumentNullException>(() => itemUnderTest.ProcessDataRows(new List<object[]>(), new List<ExcelColumnInfo>(), null).ToArray(), "Null not allowed: spreadsheetPreferences");
        }

        [Test]
        public void ProcessDataRows002_MachineNameAndConfigPathExtractedCorrectly()
        {
            var mockDataParser = new Mock<ICellDataParser>();
            var itemUnderTest = new SpreadsheetDataProcessor(mockDataParser.Object);

            var dataRows = new List<object[]>
                           {
                               new object[] {"Row1Column0", "Row1Column1", "Row1Column2", "Row1Column3"},
                               new object[] {"Row2Column0", "Row2Column1", "Row2Column2", "Row2Column3"}
                           };

            var columnHeadings = new List<ExcelColumnInfo>
                                     {
                                         new ExcelColumnInfo(0, "Column0Heading"),
                                         new ExcelColumnInfo(1, "Column1Heading"),
                                         new ExcelColumnInfo(2, "Column2Heading"),
                                         new ExcelColumnInfo(3, "Column3Heading"),
                                     };

            var settings = itemUnderTest.ProcessDataRows(dataRows, columnHeadings, SpreadsheetPreferences.GetDefaultPreferences());

            Assert.IsNotNull(settings, "settings: should not be null");

            var settingsArray = settings.ToArray();
            Assert.AreEqual(2, settingsArray.Length, "settings: incorrect count");

            Assert.AreEqual("Row1Column0", settingsArray[0].MachineName, "row1 : MachineName incorrect");
            Assert.AreEqual("Row1Column1", settingsArray[0].ConfigFilePath, "row1 : ConfigFilePath incorrect");

            Assert.AreEqual("Row2Column0", settingsArray[1].MachineName, "row2 : MachineName incorrect");
            Assert.AreEqual("Row2Column1", settingsArray[1].ConfigFilePath, "row2 : ConfigFilePath incorrect");
        }

        [Test]
        public void ProcessDataRows003_SettingsExtractedCorrectly()
        {
            var itemUnderTest = new SpreadsheetDataProcessor(new CellDataParser());

            var dataRows = new List<object[]>
                           {
                               new object[] {"Row1Column0", "Row1Column1", "Row1Column2", "Row1Column3"},
                               new object[] {"Row2Column0", "Row2Column1", "Row2Column2", "Row2Column3"}
                           };

            var columnHeadings = new List<ExcelColumnInfo>
                                     {
                                         new ExcelColumnInfo(2, "Column2Heading"),
                                         new ExcelColumnInfo(3, "Column3Heading"),
                                     };
            var settings = itemUnderTest.ProcessDataRows(dataRows, columnHeadings, SpreadsheetPreferences.GetDefaultPreferences());

            Assert.IsNotNull(settings, "settings: should not be null");

            var settingsArray = settings.ToArray();
            Assert.AreEqual(2, settingsArray.Length, "settings: incorrect count");

            // first row
            Assert.AreEqual(2, settingsArray[0].ConfigurationSettings.Length, "row1 : incorrect ConfigurationSettings count");
            
            StringAssert.AreEqualIgnoringCase("Column2Heading", settingsArray[0].ConfigurationSettings[0].Token, "row1, setting0: incorrect token");
            Assert.AreEqual("Row1Column2", settingsArray[0].ConfigurationSettings[0].Value, "row1, setting0: incorrect value");
        
            StringAssert.AreEqualIgnoringCase("Column3Heading", settingsArray[0].ConfigurationSettings[1].Token, "row1, setting1: incorrect token");
            Assert.AreEqual("Row1Column3", settingsArray[0].ConfigurationSettings[1].Value, "row1, setting1: incorrect value");

            // second row
            Assert.AreEqual(2, settingsArray[1].ConfigurationSettings.Length, "row2 : incorrect ConfigurationSettings count");

            StringAssert.AreEqualIgnoringCase("Column2Heading", settingsArray[1].ConfigurationSettings[0].Token, "row2, setting0: incorrect token");
            Assert.AreEqual("Row2Column2", settingsArray[1].ConfigurationSettings[0].Value, "row2, setting0: incorrect value");

            StringAssert.AreEqualIgnoringCase("Column3Heading", settingsArray[1].ConfigurationSettings[1].Token, "row2, setting1: incorrect token");
            Assert.AreEqual("Row2Column3", settingsArray[1].ConfigurationSettings[1].Value, "row2, setting1: incorrect value");
        }

        [Test]
        public void ProcessDataRows004_JaggedSpreadsheetThrowsError()
        {
            var itemUnderTest = new SpreadsheetDataProcessor(new CellDataParser());
            var dataRows = new List<object[]>
                               {
                                   new object[] {"Row1Column0", "Row1Column1", "Row1Column2", "Row1Column3"},
                                   new object[] {"Row2Column0", "Row2Column1", "Row2Column2"}
                               };

            var columnHeadings = new List<ExcelColumnInfo>
                                     {
                                         new ExcelColumnInfo(2, "Column2Heading"),
                                         new ExcelColumnInfo(3, "Column3Heading"),
                                     };

            Assert.Throws<SpreadsheetDataException>(() => itemUnderTest.ProcessDataRows(dataRows, columnHeadings, SpreadsheetPreferences.GetDefaultPreferences()).ToList());
        }

        [Test]
        public void ProcessDataRows005_BlankRowsAreSkipped()
        {
            var itemUnderTest = new SpreadsheetDataProcessor(new CellDataParser());
            var dataRows = new List<object[]>
                               {
                                   new object[] {"Row1Column0", "Row1Column1", "Row1Column2", "Row1Column3"},
                                   new object[] {null, null, null, null},
                                   new object[] {"Row2Column0", "Row2Column1", "Row2Column2", "Row2Column3"}
                               };

            var columnHeadings = new List<ExcelColumnInfo>
                                     {
                                         new ExcelColumnInfo(2, "Column2Heading"),
                                         new ExcelColumnInfo(3, "Column3Heading"),
                                     };
            var settings = itemUnderTest.ProcessDataRows(dataRows, columnHeadings, SpreadsheetPreferences.GetDefaultPreferences());

            Assert.IsNotNull(settings, "settings: should not be null");

            var settingsArray = settings.ToArray();
            Assert.AreEqual(2, settingsArray.Length, "settings: incorrect count");

            // first row
            Assert.AreEqual(2, settingsArray[0].ConfigurationSettings.Length, "row1 : incorrect ConfigurationSettings count");

            StringAssert.AreEqualIgnoringCase("Column2Heading", settingsArray[0].ConfigurationSettings[0].Token, "row1, setting0: incorrect token");
            Assert.AreEqual("Row1Column2", settingsArray[0].ConfigurationSettings[0].Value, "row1, setting0: incorrect value");

            StringAssert.AreEqualIgnoringCase("Column3Heading", settingsArray[0].ConfigurationSettings[1].Token, "row1, setting1: incorrect token");
            Assert.AreEqual("Row1Column3", settingsArray[0].ConfigurationSettings[1].Value, "row1, setting1: incorrect value");

            // second row
            Assert.AreEqual(2, settingsArray[1].ConfigurationSettings.Length, "row2 : incorrect ConfigurationSettings count");

            StringAssert.AreEqualIgnoringCase("Column2Heading", settingsArray[1].ConfigurationSettings[0].Token, "row2, setting0: incorrect token");
            Assert.AreEqual("Row2Column2", settingsArray[1].ConfigurationSettings[0].Value, "row2, setting0: incorrect value");

            StringAssert.AreEqualIgnoringCase("Column3Heading", settingsArray[1].ConfigurationSettings[1].Token, "row2, setting1: incorrect token");
            Assert.AreEqual("Row2Column3", settingsArray[1].ConfigurationSettings[1].Value, "row2, setting1: incorrect value");
        }

        [Test]
        public void ProcessDataRows006_SkipsRowWithNoMachineName()
        {
            var itemUnderTest = new SpreadsheetDataProcessor(new CellDataParser());
            var dataRows = new List<object[]>
                               {
                                   new object[] {null, "Row1Column1", "Row1Column2", "Row1Column3"}
                               };

            var columnHeadings = new List<ExcelColumnInfo>
                                     {
                                         new ExcelColumnInfo(2, "Column2Heading"),
                                         new ExcelColumnInfo(3, "Column3Heading"),
                                     };
            var settings = itemUnderTest.ProcessDataRows(dataRows, columnHeadings, SpreadsheetPreferences.GetDefaultPreferences());

            Assert.IsNotNull(settings, "settings: should not be null");

            var settingsArray = settings.ToArray();
            Assert.AreEqual(0, settingsArray.Length, "settings: incorrect count");
        }

        [Test]
        public void ProcessDataRows007_SkipsRowWithNoConfigFilePath()
        {
            var itemUnderTest = new SpreadsheetDataProcessor(new CellDataParser());
            var dataRows = new List<object[]>
                               {
                                   new object[] {"Row1Column0", null, "Row1Column2", "Row1Column3"}
                               };

            var columnHeadings = new List<ExcelColumnInfo>
                                     {
                                         new ExcelColumnInfo(2, "Column2Heading"),
                                         new ExcelColumnInfo(3, "Column3Heading"),
                                     };
            var settings = itemUnderTest.ProcessDataRows(dataRows, columnHeadings, SpreadsheetPreferences.GetDefaultPreferences());

            Assert.IsNotNull(settings, "settings: should not be null");

            var settingsArray = settings.ToArray();
            Assert.AreEqual(0, settingsArray.Length, "settings: incorrect count");
        }
    }
}
